package analiseSintatica.Regras.Funcao;

import java.util.LinkedList;

import AnaliseLexicaFinal.EstruturaDeDados.LinkToken;
import analiseSemantica.ErroSemantico;
import analiseSemantica.Tipos.TipoSemantico;
import analiseSemantica.Tipos.TiposSemanticos;
import analiseSemantica.estruturadedados.Identificador;
import analiseSemantica.estruturadedados.Token;
import analiseSemantica.estruturadedados.Typedef;
import analiseSintatica.AnalisadorSintatico;
import analiseSintatica.ErroSintaticoException;
import analiseSintatica.Regras.*;
import analiseSintatica.Regras.Tipos.RegraTipoPrimitivo;

public class RegraArgsDeclaracao extends Regra {

    protected static Regra instancia;
    protected String estrutura = "(<tipo_primitivo> | identificador) ['*'] identificador {',' (<tipo_primitivo> | identificador) ['*'] identificador }";

    /**
     * Construtor privado necessario ao singleton
     */
    private RegraArgsDeclaracao() {
    }

    /**
     * Retorna a unica instancia dessa classe.
     * @return
     *
     *
     */
    public static RegraArgsDeclaracao getInstance() {
        if (instancia == null) {
            instancia = new RegraArgsDeclaracao();
        }
        return (RegraArgsDeclaracao) instancia;
    }

    @Override
    public TiposSemanticos analisar(LinkedList<LinkToken> listaTokens) throws ErroSintaticoException {

        TiposSemanticos tipos = new TiposSemanticos();
        boolean erros = false;
        boolean erroatual = false;
        
        boolean primeira = true;
        
         while (listaTokens.getFirst().getLexema().equals(",") || primeira) {

            if (!primeira) {
                reconheceLexema(listaTokens, "delimitador", ",", estrutura);
            }

            Identificador id = new Identificador(null);
            String tipotemp = null;
            
            if (listaContem(RegraTipoPrimitivo.getInstance().getPrimeiro(), listaTokens.getFirst())) {
                TipoSemantico tipo = RegraTipoPrimitivo.getInstance().analisar(listaTokens).removeTipos();
            	tipotemp = (String)tipo.getNomeTipo();
            } else if (listaTokens.getFirst().getToken().equals("identificador")) {                     //se for um tipdef
            	Token token = AnalisadorSintatico.escopoatual.find(listaTokens.getFirst().getLexema());
            	if (token == null || !(token instanceof Typedef)) {
            		erros = true;
            		erroatual = true;
            		AnalisadorSintatico.errosemanticos.add(new ErroSemantico("Esse nao foi definido ", listaTokens.getFirst().getLinha()));
                } else {
                    tipotemp = (String)listaTokens.getFirst().getLexema();
                    listaTokens.removeFirst();
                }
            }

            if (listaTokens.getFirst().getLexema().equals("*")) {
            	tipotemp = "ponteiro."+tipotemp;
            	id.setPonteiro(true);
                reconheceLexema(listaTokens, "operador_multiplicacao", "*", estrutura);
            }else{
            	id.setPonteiro(false);
            }

            id.setConstante(false);
            id.setLexema(listaTokens.getFirst().getLexema());
            id.setTipo(tipotemp);
            

            
            tipos.addTipos(new TipoSemantico(tipotemp, listaTokens.getFirst().getLinha()));
            
            if(!erroatual)
            	AnalisadorSintatico.escopoatual.put(listaTokens.getFirst().getLexema(), id);
            reconheceToken(listaTokens, "identificador", estrutura);
            primeira = false;
            erroatual = false;

        }
         if(erros)
        	 return null;
         return tipos;
    }

    @Override
    protected void setPrimeiro() {
        this.primeiro.add("identificador");
        this.primeiro = getUniao(primeiro, RegraTipoPrimitivo.getInstance().getPrimeiro());
    }
}
